package com.hugang.security;

/**
 * 线程安全问题示例：多个窗口卖票，使用继承Thread方式
 * <p>
 * 方式一：同步代码块
 * 说明：在继承Thread类创建多线程方式中，慎用this充当同步监视器，可以考虑使用当前类充当同步监视器
 *
 * @author hg
 * @date 2020/6/15 10:49
 */
public class WindowThreadTest {

    public static void main(String[] args) {
//        WindowThread windowThread1 = new WindowThread();
//        WindowThread windowThread2 = new WindowThread();
//        WindowThread windowThread3 = new WindowThread();
        WindowThread2 windowThread1 = new WindowThread2();
        WindowThread2 windowThread2 = new WindowThread2();
        WindowThread2 windowThread3 = new WindowThread2();
        windowThread1.setName("窗口1");
        windowThread2.setName("窗口2");
        windowThread3.setName("窗口3");
        windowThread1.start();
        windowThread2.start();
        windowThread3.start();
    }
}

class WindowThread extends Thread {

    private static int ticket = 100;

    private static Object object = new Object();

    @Override
    public void run() {
        while (true) {
//            synchronized (object) {
            //Class clazz = WindowThread.class  类只会加载一次
            synchronized (WindowThread.class) {
                //错误的方式：this代表三个WindowThread对象
//            synchronized (this) {
                if (ticket > 0) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":卖票，票号为：" + ticket--);
                } else {
                    break;
                }
            }
        }
    }
}

class WindowThread2 extends Thread {

    private static int ticket = 100;
    private static Object object = new Object();

    @Override
    public synchronized void run() {
        while (true) {
            show();
        }
    }

    /**
     * 使用同步方法方式：同步监视器为this，仍然有线程安全问题，需要修改为静态方法，此时同步监视器为当前类的Class对象
     */
    public static synchronized void show() {
        if (ticket > 0) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":卖票，票号为：" + ticket--);
        }
    }
}